import { _decorator, Component, Node, Vec2, CCFloat } from 'cc';
const { ccclass, property } = _decorator;

/**
 * 贝塞尔曲线数据接口
 * 包含曲线的起点、控制点和终点坐标
 */
interface BezierCurveData {
    startPoint: { x: number; y: number };    // 曲线起点
    controlPoint: { x: number; y: number };  // 控制点
    endPoint: { x: number; y: number };      // 曲线终点
}

/**
 * 导出数据接口
 * 包含多条贝塞尔曲线数据和总长度
 */
interface ExportData {
    curves: BezierCurveData[];  // 贝塞尔曲线数组
    totalLength: number;        // 所有曲线的总长度
}

/**
 * 贝塞尔曲线移动组件
 * 控制物体沿贝塞尔曲线匀速移动
 */
@ccclass('BezierMover')
export class BezierMover extends Component {
    // 移动速度，可在编辑器中设置
    @property(CCFloat)
    speed: number = 100; // 单位：像素/秒

    @property(CCFloat)
    rotateOffset: number = -90; // 角度偏移量，用于调整初始朝向

    @property(Boolean)
    autoRotate: boolean = true; // 是否自动旋转

    @property(CCFloat)
    initialIndex: number = 30; // 添加初始索引属性

    // 添加moveIndex属性
    private _moveIndex: number = 0;

    /**
     * 获取当前移动索引
     */
    public get moveIndex(): number {
        return this._moveIndex;
    }

    /**
     * 设置移动索引
     * @param index 目标索引位置
     */
    public set moveIndex(index: number) {
        if (!this.distanceTable || this.distanceTable.length === 0) return;

        this._moveIndex = Math.max(0, Math.min(index, this.distanceTable.length - 1));
        const entry = this.distanceTable[this._moveIndex];
        this.currentDistance = entry.distance;

        const curve = this.curves[entry.curveIndex];
        const position = this.getPointOnCurve(curve, entry.t);
        const angle = this.getTangentAngle(curve, entry.t);

        this.updateTransform(position, angle);
    }

    /**
     * 获取移动进度（0-1）
     */
    public get progress(): number {
        return this.totalDistance > 0 ? this.currentDistance / this.totalDistance : 0;
    }

    /**
     * 设置移动进度（0-1）
     */
    public set progress(value: number) {
        const clampedValue = Math.max(0, Math.min(1, value));
        this.currentDistance = this.totalDistance * clampedValue;
        this._moveIndex = this.findIndexByDistance(this.currentDistance);

        const entry = this.distanceTable[this._moveIndex];
        const curve = this.curves[entry.curveIndex];
        const position = this.getPointOnCurve(curve, entry.t);
        const angle = this.getTangentAngle(curve, entry.t);

        this.updateTransform(position, angle);
    }

    // 私有成员变量
    private curves: BezierCurveData[] = [];          // 存储所有贝塞尔曲线数据
    private currentCurveIndex: number = 0;           // 当前所在曲线的索引
    private isMoving: boolean = false;               // 是否正在移动
    private totalDistance: number = 0;               // 所有曲线的总长度
    private currentDistance: number = 0;             // 当前已移动的距离
    private distanceTable: {
        distance: number;   // 累计距离
        t: number;         // 对应的贝塞尔曲线参数t
        curveIndex: number // 所属曲线索引
    }[] = [];
    private tableResolution: number = 1000;          // 距离表精度（越大越精确，但性能消耗越大）

    /**
     * 设置贝塞尔曲线数据
     * @param data 包含曲线数据的对象
     * @param startIndex 起始索引（可选）
     */
    public setBezierData(data: ExportData, startIndex?: number) {
        this.curves = data.curves;
        this.currentCurveIndex = 0;
        this.currentDistance = 0;
        this.buildDistanceTable();

        // 设置初始索引
        if (startIndex !== undefined) {
            this.initialIndex = startIndex;
        }
    }

    /**
     * 构建距离查找表
     * 预计算曲线上的点与实际距离的对应关系，用于实现匀速移动
     */
    private buildDistanceTable() {
        this.distanceTable = [];
        this.totalDistance = 0;

        // 遍历所有曲线
        for (let curveIndex = 0; curveIndex < this.curves.length; curveIndex++) {
            const curve = this.curves[curveIndex];
            let lastPoint = this.getPointOnCurve(curve, 0);

            // 根据精度划分曲线，计算每个点的累计距离
            for (let i = 1; i <= this.tableResolution; i++) {
                const t = i / this.tableResolution;
                const currentPoint = this.getPointOnCurve(curve, t);
                this.totalDistance += Vec2.distance(lastPoint, currentPoint);

                // 记录距离、参数t和曲线索引的对应关系
                this.distanceTable.push({
                    distance: this.totalDistance,
                    t: t,
                    curveIndex: curveIndex
                });

                lastPoint = currentPoint;
            }
        }
    }

    /**
     * 根据已行进距离获取位置
     * @param distance 已行进的距离
     * @returns 对应的位置坐标
     */
    private getPositionByDistance(distance: number): Vec2 {
        // 在距离表中查找对应的条目
        const entry = this.distanceTable.find(item => item.distance >= distance);

        if (!entry) {
            // 如果没找到，说明已经到终点
            const lastCurve = this.curves[this.curves.length - 1];
            return this.getPointOnCurve(lastCurve, 1);
        }

        // 根据找到的条目计算实际位置
        const curve = this.curves[entry.curveIndex];
        return this.getPointOnCurve(curve, entry.t);
    }

    /**
     * 更新物体位置和旋转
     * @param position 目标位置
     * @param angle 目标角度（弧度）
     */
    private updateTransform(position: Vec2, angle: number) {
        this.node.setPosition(position.x, position.y);
        if (this.autoRotate) {
            // 将弧度转换为角度，并添加偏移
            const degrees = angle * 180 / Math.PI + this.rotateOffset;
            this.node.angle = degrees;
        }
    }

    /**
     * 计算某点的切线角度
     * @param curve 贝塞尔曲线数据
     * @param t 参数t (0-1)
     * @returns 切线角度（弧度）
     */
    private getTangentAngle(curve: BezierCurveData, t: number): number {
        // 二次贝塞尔曲线的导数
        // P'(t) = 2(1-t)(P1-P0) + 2t(P2-P1)
        const t1 = 1 - t;

        const dx = 2 * t1 * (curve.controlPoint.x - curve.startPoint.x) +
            2 * t * (curve.endPoint.x - curve.controlPoint.x);
        const dy = 2 * t1 * (curve.controlPoint.y - curve.startPoint.y) +
            2 * t * (curve.endPoint.y - curve.controlPoint.y);

        return Math.atan2(dy, dx);
    }

    /**
     * 每帧更新
     * @param dt 帧间隔时间
     */
    update(dt: number) {
        if (!this.isMoving || this.curves.length === 0) return;

        // 计算这一帧要移动的距离
        const moveDistance = this.speed * dt;
        this.currentDistance += moveDistance;

        // 如果已经移动完整个路径，重新开始
        if (this.currentDistance >= this.totalDistance) {
            this.currentDistance = 0;
        }

        // 更新moveIndex
        this._moveIndex = this.findIndexByDistance(this.currentDistance);

        // 获取当前位置和角度
        const entry = this.distanceTable[this._moveIndex];
        const curve = this.curves[entry.curveIndex];
        const position = this.getPointOnCurve(curve, entry.t);
        const angle = this.getTangentAngle(curve, entry.t);

        // 更新位置和角度
        this.updateTransform(position, angle);
    }

    /**
     * 获取曲线上的点
     * 使用二次贝塞尔曲线公式计算参数t对应的点坐标
     * @param curve 贝塞尔曲线数据
     * @param t 参数t (0-1)
     * @returns 计算得到的点坐标
     */
    private getPointOnCurve(curve: BezierCurveData, t: number): Vec2 {
        const t1 = 1 - t;
        const t1Squared = t1 * t1;
        const tSquared = t * t;

        // 二次贝塞尔曲线公式: B(t) = (1-t)²P0 + 2(1-t)tP1 + t²P2
        const x = t1Squared * curve.startPoint.x +
            2 * t1 * t * curve.controlPoint.x +
            tSquared * curve.endPoint.x;

        const y = t1Squared * curve.startPoint.y +
            2 * t1 * t * curve.controlPoint.y +
            tSquared * curve.endPoint.y;

        return new Vec2(x, y);
    }

    /**
     * 开始移动
     * 初始化物体位置并开始移动
     */
    public startMove() {
        if (this.curves.length === 0) {
            console.warn('No bezier curves data available');
            return;
        }

        // 从指定索引开始
        this.jumpToIndex(this.initialIndex);
        this.isMoving = true;
    }

    /**
     * 停止移动
     * 暂停物体的移动
     */
    public stopMove() {
        this.isMoving = false;
    }

    /**
     * 根据距离找到对应的索引
     * @param distance 目标距离
     * @returns 对应的索引
     */
    private findIndexByDistance(distance: number): number {
        const index = this.distanceTable.findIndex(item => item.distance >= distance);
        return index === -1 ? this.distanceTable.length - 1 : index;
    }

    /**
     * 跳转到指定索引位置
     * @param index 目标索引
     * @param autoStart 是否自动开始移动
     */
    public jumpToIndex(index: number, autoStart: boolean = false) {
        this.moveIndex = index;
        this.isMoving = autoStart;
    }

    /**
     * 跳转到指定进度
     * @param progress 目标进度（0-1）
     * @param autoStart 是否自动开始移动
     */
    public jumpToProgress(progress: number, autoStart: boolean = false) {
        this.progress = progress;
        this.isMoving = autoStart;
    }
} 